/**
* AutoSWF - Cody Cushing. March 26, 2009
* Copyright (c) 2009 Cody Cushing
* No use restrictions. Maintain this notice in all versions. 
**/

package com.autoswf.locator
{
	import com.autoswf.core.ChainLink;
	import com.autoswf.core.Transport;
	
	import flash.errors.IllegalOperationError;
	import flash.utils.Dictionary;

	/**
	 * Locator class for providing services to requesters. Uses handler in ServiceRequest to return 
	 * requested service instance to client. If the requested service does not exist the request is 
	 * bubbled up the chain. 
	 * 
	 * to do: add support for requesting service by string id (would allow multiple instances of the same service) 
	 */
	public class Locator extends ChainLink implements ILocator
	{
		protected var services:Dictionary;
		
		
		/**
		 * Constructor.
		 */		
		public function Locator(id:String)
		{
			super(id);
			services = new Dictionary(true);
		}
		
		
		/**
		 * This function responds to a ServiceRequest as the message object of a Transport, looks the service up, 
		 * and passes it to the callback in the service request. If the service is not found, the transport is 
		 * passed up the chain.
		 * 
		 * @param param  A Transport Object containing a ServiceRequest. 
		 */		
		override public function sendUpChain(param:*):void
		{
			var transport:Transport = Transport(param);
			
			if(transport.message is ServiceRequest)
			{
				var serviceRequest:ServiceRequest = ServiceRequest(transport.message);
				
				if(services[serviceRequest.service]) /* service exists at local tier, return it */
				{
					serviceRequest.setResult(services[serviceRequest.service]);
					
					if(serviceRequest.handler != null)
					{
						serviceRequest.handler(services[serviceRequest.service]); // change this to pass the request object
					}
				}
				else /* service may exist at a higher tier */
				{
					notifyParents(transport);
				}
				return
			}
			
			if(transport.message is ServiceRegistration)
			{
				var serviceRegistration:ServiceRegistration = ServiceRegistration(transport.message);
				addService(serviceRegistration.service, serviceRegistration.registeredClass);
			}
		}
		
		
		/**
		 * Makes a service instance accessible by class definition key.
		 * 
		 * @param service     The instance of the service to be returned. 
		 * @param registerTo  The class or interface by which this service can be requested.
		 */
		public function addService(service:Object, registerTo:Class):void
		{
//			try
//			{
				registerTo(service); /* throw coersion error on invalid registration */
//			}
//			catch(error:TypeError)
//			{
//				throw new TypeError("*** Locator: you have attempted to register " + service + 
//				" to " + registerTo + ", and it just isnt having it.");
//			}
			
			if(services[registerTo] != null)
			{
				throw new IllegalOperationError("Collision on service registration key. This class functions as a multiton; only one service per key.");
			}
			
			services[registerTo] = service;
		}
		
		
		public function hasService(service:Class):Boolean
		{
			return (services[service]);
		}
		
		
		public function removeService(registeredClass:Class):void
		{
			if(services[registeredClass])
			{
				delete services[registeredClass];
			}
		}
	}
}

